﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SLRT.business.api;
using SLRT.business.src;
using System.Threading;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Windows;
using SLRT.dao.data;
using Emgu.CV;
using SLRT.usercontrols;
using TestApplication.business.src;

namespace SLRT.business.src
{
    public sealed class CaptureModel : INotifyPropertyChanged
    {
        private static readonly CaptureModel instance = new CaptureModel();
        private Database database;
        private static IBrain _brain;
        private static Thread brainThread;
        private static MovementBrain _movementBrain;
        private static Thread _movementBrainThread;
        private static Boolean _brainResultReceived;
        private static Boolean _movementBrainResultReceived;
        private static Boolean _eyeWebcamResultReceived;
        private static Boolean _capturedImageChanged;
        private static Capture _capture;
        private static MainWindow view;
        private static Bitmap _image;
        private static readonly ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
        private static bool modelStarted;
        private static IImage _iimage;
        private static Bitmap processedImage;
        private static Bitmap queryImage;

        public Bitmap QueryImage
        {
            get { return CaptureModel.queryImage; }
            set { CaptureModel.queryImage = value; OnPropertyChanged(this, new PropertyChangedEventArgs("QueryImage")); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public static readonly Object lockObject01 = new Object();
        Word currentWord;
        Random random;
        private static string completingWord;

        public string CompletingWord
        {
            get { return completingWord; }
            set { completingWord = value; OnPropertyChanged(this, new PropertyChangedEventArgs("CompletingWord")); }
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(sender, e);
            }
        }


        #region Properties

        public Bitmap Image
        {

            get
            {
                rwlock.EnterWriteLock();
                try
                {
                    return new Bitmap(_image);
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
            set
            {
                rwlock.EnterWriteLock();
                try
                {
                    _image = value;
                    if (value != null)
                    {
                        OnPropertyChanged(this, new PropertyChangedEventArgs("Image"));

                        if (_movementBrain != null && !_movementBrain.NewImageFromWebcam)
                        {
                            _movementBrain.NewImageFromWebcam = true;
                        }
                    }
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
        }

        public Bitmap ProcessedImage
        {
            get { return CaptureModel.processedImage; }
            set { CaptureModel.processedImage = value; OnPropertyChanged(this, new PropertyChangedEventArgs("ProcessedImage")); }
        }

        public IImage Iimage
        {
            get { return CaptureModel._iimage; }
            set { CaptureModel._iimage = value; }
        }

        public MainWindow View
        {
            get { return CaptureModel.view; }
            set { CaptureModel.view = value; }
        }

        public Capture Capture
        {
            get { return CaptureModel._capture; }
            set { CaptureModel._capture = value; }
        }

        public Boolean CapturedImageChanged
        {
            get { return _capturedImageChanged; }
            set { _capturedImageChanged = value; }
        }

        public static Boolean EyeWebcamResultReceived
        {
            get { return _eyeWebcamResultReceived; }
            set { _eyeWebcamResultReceived = value; }
        }

        public Boolean MovementBrainResultReceived
        {
            get { return _movementBrainResultReceived; }
            set { _movementBrainResultReceived = value; }
        }

        public Boolean BrainResultReceived
        {
            get { return _brainResultReceived; }
            set
            {
                lock (lockObject01)
                {
                    _brainResultReceived = value;
                }
            }
        }

        #endregion

        public CaptureModel()
        {

            Capture = new Capture(1);
            if (!Database.LETTERS_XML_FILE.Exists)
            {
                Database.generateLettersXML();
            }
            if (!Database.WORDS_XML_FILE.Exists)
            {
                Database.generateDictionaryXML();
            }

            database = new Database();
            database.load();

            //_brain = new Brain();

            random = new Random();
            currentWord = Words[random.Next(Words.Count)];

            //CompletingWord = currentWord.WordName;
            CompletingWord = "";
            QueryImage = currentWord.WordImage;

            _image = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
            processedImage = ImageProcessing.NewEmptyImage(320, 240, Color.Black);


        }


        public List<Letter> Letters
        {
            get { return this.database.Letters; }
        }

        public List<Word> Words
        {
            get { return this.database.Words; }
        }

        public static CaptureModel Instance
        {
            get
            {
                return CaptureModel.instance;
            }
        }

        void createBrain()
        {
            int[] coordinates = new int[4];
            coordinates[0] = (int)Math.Round((double)Image.Width / 10);
            coordinates[1] = (int)Math.Round((double)Image.Height / 3);
            coordinates[2] = (int)Math.Round((double)Image.Width / 10 + (double)Image.Width / 3);
            coordinates[3] = (int)Math.Round((double)(2 * Image.Height) / 3);

            _brain = new Brain(coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
            brainThread = new Thread(new ThreadStart(_brain.ThreadRun));
            brainThread.Start();
        }

        void mainView_Loaded(object sender, RoutedEventArgs e)
        {
            createBrain();
        }

        public void InitMovementBrain()
        {
            ButtonBarControl buttonBar = null;
            for (int i = 0; i < view.mainView.MainGrid.Children.Count; i++)
            {
                if (view.mainView.MainGrid.Children[i].GetType() == typeof(ButtonBarControl))
                {
                    buttonBar = (ButtonBarControl)view.mainView.MainGrid.Children[i];
                    break;
                }
            }
            _movementBrain = new MovementBrain(buttonBar, view.mainView.WebcamControl.WebcamImage);
            _movementBrain.RunThread = true;
            _movementBrainThread = new Thread(new ThreadStart(_movementBrain.Run));
            _movementBrain.BarEvent += new PropertyChangedEventHandler(movementBrain_ButtonPressed);

        }

        public void StopWebcam()
        {
            if (_movementBrain != null)
            {
                _movementBrain.RunThread = false;
            }
            _brain.stopAlgorithmRunning();
            modelStarted = false;
        }

        public void MovementResultReceived(object sender, EventArgs args)
        {
            MovementBrainResultReceived = true;
        }

        void movementBrain_ButtonPressed(object sender, PropertyChangedEventArgs e)
        {
            string[] commands = e.PropertyName.Split(',');
            if (commands[0] == "BUTTON")
            {
                int index = Convert.ToInt32(commands[1]);
                switch (index)
                {
                    case 0:
                        Console.WriteLine("Button0 Play");
                        View.Dispatcher.BeginInvoke(new Action(delegate() { View.mainView.resultControl.Opacity = 1; }));
                        if (_brain == null)
                        {
                            createBrain();
                        }
                        _brain.startAlgorithmRunning();
                        break;
                    case 1:
                        Console.WriteLine("Button1Back");
                        if (CompletingWord.Length > 0)
                        {
                            CompletingWord = CompletingWord.Substring(0, CompletingWord.Length - 1);
                        }
                        break;
                    case 2:
                        Console.WriteLine("Button2Next word");
                        CompletingWord = "";
                        currentWord = database.Words.ElementAt(new Random().Next(database.Words.Count));
                        QueryImage = currentWord.WordImage;
                        break;
                    case 3:
                        Console.WriteLine("Button3Stop");
                        if (_brain != null)
                        {
                            _brain.stopAlgorithmRunning();
                        }
                        View.Dispatcher.BeginInvoke(new Action(delegate() { View.mainView.resultControl.Opacity = 0; }));
                        break;
                    default:
                        Console.WriteLine("Button index does not exist");
                        break;
                }
            }
        }

        public void ThreadRun()
        {
            while (true)
            {
                IImage img = _capture.QueryFrame();
                Bitmap image = img.Bitmap;
                CaptureModel.Instance.Iimage = img;
                image.RotateFlip(RotateFlipType.RotateNoneFlipX);
                CaptureModel.Instance.Image = image;

                if (_movementBrainThread != null && !_movementBrainThread.IsAlive)
                {
                    _movementBrainThread.Start();
                }


                if (_brainResultReceived)
                {                    
                    BrainResultReceived = false;

                    String letterStringLetterStringLetter;
                    int newResult = _brain.Result;
                    if (newResult == -1)
                    {
                        letterStringLetterStringLetter = "_";
                    }
                    else
                    {
                        letterStringLetterStringLetter = Letters[newResult].LetterName;
                    }

                    if (CompletingWord.Length < currentWord.WordName.Length)
                    {
                        View.Dispatcher.BeginInvoke(new Action(delegate() { View.mainView.resultControl.SetCurrentLetter(letterStringLetterStringLetter); }));

                        if (letterStringLetterStringLetter.ToLower().Equals(currentWord.WordName.ElementAt(CompletingWord.Length).ToString()))
                        {
                            CompletingWord += letterStringLetterStringLetter;
                        }
                    }
                    else
                    {
                        View.Dispatcher.BeginInvoke(new Action(delegate() { View.mainView.resultControl.SetCurrentLetter(""); }));
                    }

                }

                Thread.Sleep(30);
            }

        }
    }
}
